package clueless.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import clueless.utilities.*;

public class Server extends Logger {

	private ArrayList<GameServer> m_gameServers;
	
	private GameServer findGameServer(int desiredNumPlayers, String desiredCharacter) {

		// Check if valid game server already exists
		int gameServerIndex = -1;

		for (int i = 0; i < m_gameServers.size(); i++) {

			GameServer gameServer = m_gameServers.get(i);
			
			if ((gameServer.getNumDesiredPlayers() == desiredNumPlayers) &&
					(gameServer.isCharacterUnclaimed(desiredCharacter))) {

				gameServerIndex = i;
				break;

			}

		}

		// If no valid game exists, add new one to end of list
		if (gameServerIndex == -1) {

			m_gameServers.add(new GameServer(desiredNumPlayers));
			gameServerIndex = m_gameServers.size() - 1;

		}

		return m_gameServers.get(gameServerIndex);

	}
	
	private void run() throws IOException {

		logPrint("Server starting");
		
		// Setup server socket to listen for new clients
		ServerSocket serverSocket = null;
		
		try {
			serverSocket = new ServerSocket(Constants.m_SERVER_PORT);
		}
		catch(IOException ex) {
			ex.printStackTrace();
		}
		
		logPrint("Listening for clients on port " + Constants.m_SERVER_PORT);

		// Continuously listen for new clients
		try {

			while(true) {

				// Block until new client is found
				Socket clientSocket = serverSocket.accept();

				// Setup a connection with new client
				Connection clientConnection = new Connection();
				clientConnection.connectToClient(clientSocket);

				// Get new client 'join game' information
				String message = Message.getMessage(clientConnection.getInputStream());
				logPrint(message);
				
				// Add new client to game server (or spawn new one, if need be)
				int    desiredNumPlayers = Integer.parseInt(Message.getValue(Message.m_DESIRED_NUM_PLAYERS, message));
				String desiredCharacter  =                  Message.getValue(Message.m_CHARACTER          , message);
				
				GameServer chosenGameServer = findGameServer(desiredNumPlayers, desiredCharacter);
				
				Player newPlayer = new Player(desiredCharacter, clientConnection);
				chosenGameServer.addPlayer(newPlayer);

				// Tell players that a new played has joined
				Message.sendPlayerJoinedMessage(chosenGameServer.getPlayers(), newPlayer, 
					                            chosenGameServer.getNumRemainingPlayers());

				// Start game if all of its players are now present
				if (chosenGameServer.getNumRemainingPlayers() == 0) {
					
					// Pop game server off of list so it can run as an independent thread
					m_gameServers.remove(chosenGameServer);

					// Start chosen game in its own thread
					Thread gameRunnerThread = new Thread(new GameRunner(chosenGameServer));
					gameRunnerThread.start();
			
				}
		
			}

		}
	   	catch(IOException ex) {
			serverSocket.close();
	   		ex.printStackTrace();
	   	}

	}

	public class GameRunner implements Runnable {
		
		GameServer m_gameServer;
		
		public GameRunner(GameServer gameServer){
		
			m_gameServer = gameServer;

		}

		public void run() {

			logPrint("Thread running");

			while(true) {
				m_gameServer.playGame();
			}

		}

	}
	
	
	public Server() {

		super("Server");
		
		m_gameServers = new ArrayList<GameServer>();

	}
	
	public static void main(String[] args) {

		try {
			new Server().run();
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}

	}

}
